module character;

import std.uni;
import std.ctype;
debug import std.stdio;

final class Character {
    private this() {
    }

    public static bool isAlNum(char c) {
        return isAlpha(c) || isDigit(c);
    }

    public static bool isAlpha(char c) {
        return isUniAlpha(c) != 0;
    }

    public static bool isControl(char c) pure {
        return iscntrl(c) != 0;
    }

    public static bool isLower(char c) {
        return isUniLower(c) != 0;
    }

    public static bool isPunct(char c) pure {
        return ispunct(c) != 0;
    }

    public static bool isSpace(char c) pure {
        return isspace(c) != 0;
    }

    public static bool isUpper(char c) {
        return isUniUpper(c) != 0;
    }

    public static bool isGraph(char c) pure {
        return isgraph(c) != 0;
    }

    public static bool isPrint(char c) pure {
        return isprint(c) != 0;
    }

    public static char toUpper(char c) {
        return cast(char)toUniUpper(c);
    }

    public static char toLower(char c) {
        return cast(char)toUniLower(c);
    }

    public static bool isDigit(in char value, in ubyte radix = 10)
    in {
        assert((radix >= 2) && (radix <= 36));
    }
    body {
        if (radix <= 10) {
            return ((value >= '0') && (value < ('0' + radix)));
        } else {
            if ((value >= '0') && (value <= '9')) {
                return true;
            } else {
                char c = toLower(value);
                return (c >= 'a' - 10) && (c < 'a' + radix - 10);
            }
        }
    }

    public static int toDigit(in char value) {
            if ((value >= '0') && (value <= '9')) {
                return value - '0';
            } else {
                char c = toLower(value);
                return c - 'a' + 10;
            }
    }

    unittest {
        assert(isAlpha('i'));
        assert(isAlpha('m'));
        assert(isAlpha('I'));
        assert(isAlpha('A'));
        assert(isAlpha('a'));
        assert(isAlpha('Z'));
        assert(isAlpha('z'));
        assert(isAlpha('w'));
        assert(isAlpha('B'));
        assert(isAlpha('q'));
        assert(!isAlpha(' '));
        assert(!isAlpha('\t'));
        assert(isDigit('0'));
        assert(isDigit('1'));
        assert(isDigit('2'));
        assert(isDigit('3'));
        assert(isDigit('4'));
        assert(isDigit('5'));
        assert(isDigit('6'));
        assert(isDigit('7'));
        assert(isDigit('8'));
        assert(isDigit('9'));
        assert(!isDigit('A'));
        assert(!isDigit('a'));
        assert(!isDigit('Z'));
        assert(!isDigit('z'));
        assert(!isDigit('E'));
        assert(!isDigit('e'));
        assert(!isDigit(' '));
        assert(!isDigit('\n'));
        assert(toLower('A') == 'a');
        assert(toLower('C') == 'c');
        assert(toLower('c') == 'c');
        assert(toLower('Z') == 'z');
        assert(toLower(' ') == ' ');
        assert(toLower('4') == '4');
        assert(isDigit('a', 16));
        assert(isDigit('A', 16));
        assert(isDigit('F', 16));
        assert(!isDigit('G', 16));
        assert(isDigit('z', 36));
        assert(isDigit('Z', 36));
        assert(isDigit('7', 8));
        assert(!isDigit('8', 8));
        assert(!isDigit('\'', 16));

        assert(toDigit('0') == 0);
        assert(toDigit('1') == 1);
        assert(toDigit('2') == 2);
        assert(toDigit('3') == 3);
        assert(toDigit('4') == 4);
        assert(toDigit('5') == 5);
        assert(toDigit('6') == 6);
        assert(toDigit('7') == 7);
        assert(toDigit('8') == 8);
        assert(toDigit('9') == 9);
        assert(toDigit('a') == 10);
        assert(toDigit('b') == 11);
        assert(toDigit('C') == 12);
        assert(toDigit('d') == 13);
        assert(toDigit('e') == 14);
        assert(toDigit('F') == 15);
        assert(toDigit('g') == 16);
        assert(toDigit('h') == 17);
    }
}
